package com.sz.biz.common.sup.service.impl;

import com.sz.biz.common.utils.PassWordCreate;
import com.sz.biz.common.constants.ErrorCodes;
import com.sz.biz.common.constants.ModuleNames;
import com.sz.biz.common.sup.entity.SupUser;
import com.sz.biz.common.sup.service.SupplierUserService;
import com.sz.biz.common.sup.dto.SuperUserDto;
import com.sz.common.base.constants.TemplateConstants;
import com.sz.common.base.constants.UserActions;
import com.sz.common.base.dao.ParamData;
import com.sz.common.base.dto.QResultDto;
import com.sz.common.base.dto.QueryParams;
import com.sz.common.base.exception.Exceptions;
import com.sz.common.base.service.AbstractService;
import com.sz.common.core.service.PrincipalLogUtils;
import com.sz.common.core.system.service.SysMailService;
import com.sz.common.base.utils.CheckDataUtils;
import com.sz.common.base.utils.CredentialUtils;
import com.sz.common.base.utils.JsonUtils;
import com.sz.common.base.utils.StringUtils;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Function: TODO: ADD FUNCTION <br>
 * Author: Johnboy <br>
 * Date: 2017-10-11 14:47:00
 */
@Service
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
public class SupplierUserServiceImpl extends AbstractService implements SupplierUserService {

    private static final String FOOT_LINE = "_";
    private static final String MID_LINE = "-";
    @Autowired
    private SysMailService mailService;

    @Override
    protected String getMapperNamespace() {
        return "SupUserMapper";
    }

    @Override
    public int save(SupUser entry) {
        if (entry != null) {
            if (entry.getPassword() == null || "".equalsIgnoreCase(entry.getPassword())) {
                PassWordCreate pwc = new PassWordCreate();
                String pswd = pwc.createPassWord(6);
                entry.setPassword(pswd);
            }
            checkDataValid(entry);
            checkUserExist(entry);
            String credentialSalt = CredentialUtils.generateSalt();
            entry.setCredentialSalt(credentialSalt);
            String tempPswd = entry.getPassword();
            String encryptionPswd = encryptionProc(entry.getPassword(), credentialSalt);
            entry.setPassword(encryptionPswd);
            dao.save(getSqlName("insertSelective"), entry);
            Map<String,Object> emailBodyMap = new HashMap<>();
            emailBodyMap.put("username",entry.getUserName());
            emailBodyMap.put("password",tempPswd);
            String emailBody = JsonUtils.toJSONString(emailBodyMap);

            // 发邮件
            mailService.createMail("sys.logistics.master@hna.com", new String[]{entry.getEmail()},
                    "供应商账号初始密码通知",
                    emailBody, TemplateConstants.INIT_PASSWORD);
            Map<String, Object> dataBackup = new HashMap<>();
            dataBackup.put("ADD_SUPPLIER_USER", entry);
            PrincipalLogUtils.addOperationLog(ModuleNames.SUP, ModuleNames.SUP_USER, UserActions.ADD, "新建供应商账号", dataBackup);
        }
        return 0;
    }

    private void checkUserExist(SupUser supUser) {
        Map<String, Object> map = new HashMap<>();
        map.put("id", supUser.getId());
        map.put("email", supUser.getEmail());
        SupUser supUserExist = (SupUser) dao.findForObject(getSqlName("findByEmail"), map);
        if (supUserExist != null) {
            throw Exceptions.bizException(ErrorCodes.ERROR_SUPPLIER_USER_EMAIL_EXIST);
        }
        map = new HashMap<>();
        map.put("id", supUser.getId());
        map.put("userName", supUser.getUserName());
        supUserExist = (SupUser) dao.findForObject(getSqlName("findByUserName"), map) ;
        if (supUserExist != null) {
            throw Exceptions.bizException(ErrorCodes.ERROR_MODEL_NAME_EXIST, supUserExist.getUserName());
        }
        if (this.checkMobilePhoneExist(supUser.getId(),supUser.getMobilePhone())) { // 电话唯一校验
            throw Exceptions.bizException(ErrorCodes.ERROR_SUPPLIER_USER_PHONE_EXIST, supUserExist.getMobilePhone());
        }
    }

    private void checkDataValid(SupUser entry) {
        if (StringUtils.isEmpty(entry.getUserName())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "username");
        }
        if (StringUtils.isEmpty(entry.getFullName())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "fullname");
        }
        if (StringUtils.isEmpty(entry.getMobilePhone())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "mobilephone");
        }
        if (StringUtils.isEmpty(entry.getEmail())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "email");
        }
        if (entry.getRefSupplier() == 0) {
            throw Exceptions.bizException(ErrorCodes.ERROR_ARGUMENT_EMPTY, "supplierId");
        }
    }

    @Override
    public void batchSave(List<SupUser> list) {
        if (list != null && list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                checkDataValid(list.get(i));
                checkUserExist(list.get(i));
                String credentialSalt = CredentialUtils.generateSalt();
                list.get(i).setCredentialSalt(credentialSalt);
                String encryptionPswd = encryptionProc(list.get(i).getPassword(), credentialSalt);
                list.get(i).setPassword(encryptionPswd);
            }
            dao.batchInsert(getSqlName("insertSelective"), list);
        }
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("ADD_SUPPLIER_USER", list);
        PrincipalLogUtils.addOperationLog(ModuleNames.SUP, ModuleNames.SUP_USER, UserActions.ADD, "批量新建供应商账号", dataBackup);

    }

    @Override
    public void batchDelete(List<Integer> ids) {
        if (ids != null && ids.size() > 0) {
            for (int i = 0; i < ids.size(); i++) {
                SupUser SupUser = (SupUser) dao.findForObject(getSqlName("findById"), ids.get(i));
                if (SupUser.getIsSystem()) {
                    throw Exceptions.bizException(ErrorCodes.ERROR_SUPPLIER_NOT_DELETED_CAUSEDBY_ADMIN);
                }
            }
            dao.update(getSqlName("deleteByIds"), ids);
        }
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("DELETE_SUPPLIER_USER", ids);
        PrincipalLogUtils.addOperationLog(ModuleNames.SUP, ModuleNames.SUP_USER, UserActions.DELETE, "批量删除供应商账号", dataBackup);
    }

    @Override
    public void lockSupplierUser(List<Integer> ids) {
        if (ids != null && ids.size() > 0) {
            List<Integer> mainAccountIds = new ArrayList<Integer>();
            for (int i=0; i<ids.size(); i++) {
                SupUser supUser = (SupUser) dao.findForObject(getSqlName("selectByPrimaryKey"), ids.get(i));
                if (supUser.getIsSystem()) {
                    mainAccountIds.add(supUser.getRefSupplier());
                }
            }
            if(mainAccountIds.size()>0){
                dao.update(getSqlName("lockUserByRefSupplier"),mainAccountIds);
            }else {
                dao.update(getSqlName("lockUser"),ids);
            }
        }
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("LOCK_SUPPLIER", ids);
        PrincipalLogUtils.addOperationLog(ModuleNames.SUP, ModuleNames.SUP_USER, UserActions.LOCK, "锁定供应商账号", dataBackup);
    }

    @Override
    public void unlockSupplierUser(List<Integer> ids) {
        if (ids != null && ids.size() > 0) {
            List<Integer> mainAccountIds = new ArrayList<Integer>();
            for (int i=0; i<ids.size(); i++) {
                SupUser supUser = (SupUser) dao.findForObject(getSqlName("selectByPrimaryKey"), ids.get(i));
                if (supUser.getIsSystem()) {
                    mainAccountIds.add(supUser.getRefSupplier());
                }
            }
            if(mainAccountIds.size()>0){
                dao.update(getSqlName("unlockUserByRefSupplier"),mainAccountIds);
            }else {
                dao.update(getSqlName("unlockUser"),ids);
            }
        }
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("UNLOCK_SUPPLIER_USER", ids);
        PrincipalLogUtils.addOperationLog(ModuleNames.SUP, ModuleNames.SUP_USER, UserActions.UNLOCK, "解锁供应商账号", dataBackup);
    }

    @Override
    public void updateSupplierUser(List<SupUser> list) {
        if (list != null && list.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                checkDataValid(list.get(i));
                checkUserExist(list.get(i));
                SupUser cusUserInfo = (SupUser) dao.findForObject(getSqlName("selectByPrimaryKey"), list.get(i).getId());
                if (list.get(i).getPassword() != null && "".equalsIgnoreCase(list.get(i).getPassword())) {
                    String encryptionPswd = encryptionProc(list.get(i).getPassword(), cusUserInfo.getCredentialSalt());
                    list.get(i).setPassword(encryptionPswd);
                }
            }

            dao.batchUpdate(getSqlName("updateByPrimaryKeySelective"), list);
        }
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("UPDATE_SUPPLIER_USER", list);
        PrincipalLogUtils.addOperationLog(ModuleNames.SUP, ModuleNames.SUP_USER, UserActions.UPDATE, "更新供应商账号", dataBackup);
    }

    @Override
    public void resetUsersPasswd(List<Integer> userIds) {
        for (Integer userId : userIds) {
            SupUser supUser = (SupUser) dao.findForObject(getSqlName("selectByPrimaryKey"), userId);
            if (supUser != null) {
                String randomPassword = CredentialUtils.randomPassword();
                supUser.setPassword(new Md5Hash(randomPassword, supUser.getCredentialSalt()).toString());
                dao.update(getSqlName("updatePasswordById"), supUser);

                Map<String,Object> emailBodyMap = new HashMap<>();
                emailBodyMap.put("username",supUser.getUserName());
                emailBodyMap.put("password",randomPassword);
                String emailBody = JsonUtils.toJSONString(emailBodyMap);
                // 发邮件
                mailService.createMail("sys.logistics.master@hna.com", new String[]{supUser.getEmail()},
                        "供应商账号密码重置通知",
                        emailBody, TemplateConstants.RESET_PASSOWRD);
            }
        }
        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("UPDATE_SUPPLIER_USER", userIds);
        PrincipalLogUtils.addOperationLog(ModuleNames.SUP, ModuleNames.SUP_USER, UserActions.UPDATE, "重置客户账号密码", dataBackup);

    }

    @Override
    public boolean checkMobilePhoneExist(Integer userId, String mobilePhone) {
        if (FOOT_LINE.equals(mobilePhone) || MID_LINE.equals(mobilePhone)) {
            return false;
        }
        Map<String, Object> map = new HashMap<>();
        if (userId != null && userId > 0) {
            map.put("id", userId);
        }
        map.put("mobilePhone", mobilePhone);
        boolean isExist = false;
        List<SupUser> cusUserList = dao.findForList(getSqlName("findByMobilephone"), map, SupUser.class);
        if (cusUserList != null && cusUserList.size() > 0) {
            isExist = true;
        }
        return isExist;
    }

    @Override
    public SupUser findByAccountName(String accountName) {
        SupUser supUser = (SupUser) dao.findForObject(getSqlName("findByCustomerAccount"), accountName);
        return supUser;
    }

    @Override
    public void changePassword(int id, String oldPassword, String password) {
        SupUser queryRes = (SupUser) dao.findForObject(getSqlName("selectByPrimaryKey"), id);
        if (queryRes == null) {
            throw Exceptions.bizException(ErrorCodes.ERROR_MODEL_NOT_FOUND, id);
        }
        String oldHash = new Md5Hash(oldPassword, queryRes.getCredentialSalt()).toString();
        if (!oldHash.equalsIgnoreCase(queryRes.getPassword())) {
            throw Exceptions.bizException(ErrorCodes.ERROR_SUPPLIER_USER_OLD_PASS_NOT_MATCH);
        }
        if (!CheckDataUtils.checkPasswordAnySpecCharacter(password)) {
            throw Exceptions.bizException(ErrorCodes.ERROR_SUPPLIER_USER_PASSWORD_FORMAT_ERROR);
        }
        String updatePassword = new Md5Hash(password, queryRes.getCredentialSalt()).toString().toUpperCase();
        SupUser supUser = new SupUser();
        supUser.setId(queryRes.getId());
        supUser.setPassword(updatePassword);
        dao.update(getSqlName("updatePasswordById"), supUser);

        Map<String, Object> dataBackup = new HashMap<>();
        dataBackup.put("CHANGE_SUPPLIER_USER_PASSWORD", queryRes);
        PrincipalLogUtils.addOperationLog(ModuleNames.SUP, ModuleNames.SUP_USER, UserActions.UPDATE, "更改供应商客户账号密码", dataBackup);
    }

    @Override
    public QResultDto find(String q, int pageIndex, int pageSize, String sortName, boolean isAsc, int refSupplier) {
        ParamData pd = this.convertQueryParams(new QueryParams(pageSize, pageIndex, q, sortName, isAsc).put("refSupplier", refSupplier));
        List<SupUser> supUsers = dao.findForList(getSqlName("findByParamListPage"), pd, SupUser.class);
        List<SuperUserDto> superUserDtos = new ArrayList<>();
        if (supUsers != null && supUsers.size() > 0) {
            supUsers.forEach(supUser -> {
                SuperUserDto superUserDto = new SuperUserDto();
                BeanUtils.copyProperties(supUser, superUserDto);
                superUserDtos.add(superUserDto);
            });
        }
        QResultDto qResultDto = new QResultDto();
        qResultDto.setData(superUserDtos);
        qResultDto.setPagination(pd.getPagination());
        return qResultDto;
    }

    private String encryptionProc(String pswd, String credentialSalt) {
        return new Md5Hash(pswd, credentialSalt).toString();
    }
}
